#include "wifi_adapter.h"
#include "iot_uart.h"
#include "los_list.h"
#include "stm32f4xx_ll_usart.h"
#include "stm32f4xx_ll_bus.h"
#include "queue.h"
#include "ll_gpio.h"
#include "ll_uart.h"
#include "ctype.h"
#include "stdint.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"

/*
AT version:1.3.0.0(Jul 14 2016 18:54:01)
SDK version:2.0.0(656edbf)
compile time:Jul 19 2016 18:44:44
OK

WIFI DISCONNECT

WIFI CONNECTED
WIFI GOT IP

+STA_CONNECTED:"f2:bd:c0:a9:b0:37"
+DIST_STA_IP:"f2:bd:c0:a9:b0:37","192.168.4.2"

+STA_DISCONNECTED:"f2:bd:c0:a9:b0:37"
*/
extern UART_Config g_uartConfig[UART_MAX];
extern QueueInfo g_queueInfo[QUEUE_MAX];
extern uint8_t g_stationQueue;
extern uint8_t g_scanQueue;
extern uint8_t g_deviceConfigQueue;
extern uint8_t g_wifiEventQueue;
static char rsp_buf[1024];
uint8_t g_ESP8266_MsgQueue = 0xff;

// 字符串mac转为6个hex
void mac_str2hex(char *dst, char *src)
{
    int i;
    char tmp[2];
    for (i = 0; i < 6; i++)
    {
        memcpy(tmp, &src[i * 3], 2);
        for (int j = 0; j < 2; j++)
        {
            // 大写转小写
            if (tmp[j] >= 'A' && tmp[j] <= 'Z')
                tmp[j] = tolower(tmp[j]);
            // 字符转数字
            if (tmp[j] >= '0' && tmp[j] <= '9')
                tmp[j] = tmp[j] - '0';
            else if (tmp[j] >= 'a' && tmp[j] <= 'z')
                tmp[j] = tmp[j] - 87;
        }
        dst[i] = tmp[0] * 16 + tmp[1];
    }
}
// hex数组转为mac字符串
void mac_hex2str(char *dst, char *src)
{
    int i;
    for (i = 0; i < 6; i++)
    {
        sprintf(dst + i * 3, "%02x", src[i]);
        if (i != 0)
            dst[i * 3 - 1] = ':';
    }
}
// 字符串ip转为整数
uint32_t ip_to_int(char *ip)
{
    char a[4] = {0};
    char b[4] = {0};
    char c[4] = {0};
    char d[4] = {0};
    int i, l = 0, m = 0, n = 0;
    for (i = 0; i < strlen(ip); i++)
    {
        if (ip[i] == '.')
        {
            if (l == 0)
                l = i;
            else if (m == 0)
                m = i;
            else if (n == 0)
                n = i;
        }
    }
    memcpy(a, ip, l);
    memcpy(b, ip + l + 1, m - l - 1);
    memcpy(c, ip + m + 1, n - m - 1);
    memcpy(d, ip + n + 1, strlen(ip) - n - 1);
    return ((unsigned int)atoi(a) << 24) + ((unsigned int)atoi(b) << 16) + ((unsigned int)atoi(c) << 8) + atoi(d);
}
// 整数ip转为字符串
void int_to_ip(char *ip_str, uint32_t ip_int)
{
    sprintf(ip_str, "%ld.%ld.%ld.%ld", (ip_int >> 24) & 0xff, (ip_int >> 16) & 0xff, (ip_int >> 8) & 0xff, (ip_int >> 0) & 0xff);
}
// channel转频率
unsigned int ChannelToFrequency(unsigned int channel)
{
    if (channel <= 0){
        return 0;
    }
    if (channel == CHANNEL_80211B_ONLY){
        return FREQ_OF_CHANNEL_80211B_ONLY;
    }
    return (((channel - WIFI_MIN_CHANNEL) * WIFI_FREQ_INTERVAL) + FREQ_OF_CHANNEL_1);
}
// 频率转channel
unsigned int FrequencyToChannel(unsigned int frequency)
{
    if (frequency == FREQ_OF_CHANNEL_80211B_ONLY){
        return CHANNEL_80211B_ONLY;
    }
    if (frequency < FREQ_OF_CHANNEL_1){
        return 0;
    }
    return (frequency - FREQ_OF_CHANNEL_1) / WIFI_FREQ_INTERVAL + WIFI_MIN_CHANNEL;
}
// 根据 WifiErrorCode 输出错误信息
void PrintWifiError(WifiErrorCode res)
{
    switch(res)
    {
        case WIFI_SUCCESS: printf("Success ...\n"); break;
        case ERROR_WIFI_INVALID_ARGS: printf("Failed, reason is : ERROR_WIFI_INVALID_ARGS\n"); break;
        case ERROR_WIFI_CHIP_INVALID: printf("Failed, reason is : ERROR_WIFI_CHIP_INVALID\n"); break;
        case ERROR_WIFI_IFACE_INVALID: printf("Failed, reason is : ERROR_WIFI_IFACE_INVALID\n"); break;
        case ERROR_WIFI_RTT_CONTROLLER_INVALID: printf("Failed reason is : ERROR_WIFI_RTT_CONTROLLER_INVALID\n"); break;
        case ERROR_WIFI_NOT_SUPPORTED: printf("Failed, reason is : ERROR_WIFI_NOT_SUPPORTED\n"); break;
        case ERROR_WIFI_NOT_AVAILABLE: printf("Failed, reason is : ERROR_WIFI_NOT_AVAILABLE\n"); break;
        case ERROR_WIFI_NOT_STARTED: printf("Failed, reason is : ERROR_WIFI_NOT_STARTED\n"); break;
        case ERROR_WIFI_BUSY: printf("Failed, reason is : ERROR_WIFI_BUSY\n"); break;
        case ERROR_WIFI_INVALID_PASSWORD: printf("Failed, reason is : ERROR_WIFI_INVALID_PASSWORD\n"); break;
        case ERROR_WIFI_UNKNOWN: printf("Failed, reason is : ERROR_WIFI_UNKNOWN\n"); break;
        default: break;
    }
}
// 串口初始化
int WifiUartInit()
{
#if WIFI_DEBUG
    printf("======================\n");
    printf("Init ESP8266 Uart ...\n");
    //fflush(stdout);
#endif
    // 初始化串口
    IotUartAttribute param;
    param.baudRate = 115200;
    param.dataBits = IOT_UART_DATA_BIT_8;
    param.parity = IOT_UART_PARITY_NONE;
    param.stopBits = IOT_UART_STOP_BIT_1;
    int res = IoTUartInit(AT_USART_PORT, &param);
    return res;
}
// 复位模块
WifiErrorCode WifiReset()
{
#if WIFI_DEBUG
    printf("======================\n");
    printf("Reset ESP8266 ... \n");
    //fflush(stdout);
#endif
    WifiErrorCode res;
    g_scanQueue = 0xff;
    g_wifiEventQueue = 0xff;
    g_deviceConfigQueue = 0xff;
    g_ESP8266_MsgQueue = 0xff;
	// 发送指令
    SendWifiCommand(WIFI_RESET, NULL);
    res = WaitWifiResponse(WIFI_RESET, NULL, WIFI_TIMEOUT);
#if WIFI_DEBUG
    PrintWifiError(res);
#endif
    return res;
}

void ParseWifiScanResult(char *buf, WifiScanInfo *info)
{
    // 4,"Xiaomi_9F9E",-80,"f0:b4:29:e2:9f:9f",1,-7,0)
    char enc[2]={0}, rssi[4]={0}, mac[17]={0}, channel[3]={0};
    char *tmp, *saveptr;
    int tmp_len;
    // 加密方式
    tmp = strtok_r(buf, ",", &saveptr);
    if(tmp != NULL){
        tmp_len = strlen(tmp);
        memcpy(enc, tmp, tmp_len);
        tmp = strtok_r(NULL, ",", &saveptr);
        if(enc[0] == 0){
            info->securityType = WIFI_SEC_TYPE_OPEN;
        }
        else if(enc[0] == 1){
            info->securityType = WIFI_SEC_TYPE_WEP;
        }
        else if(enc[0] == 2){
            info->securityType = WIFI_SEC_TYPE_PSK;
        }
        else{
            info->securityType = WIFI_SEC_TYPE_INVALID;
        }
    }
    else{
        return;
    }
    // ssid
    if(tmp != NULL){
        tmp_len = strlen(tmp);
        memset(info->ssid, 0, WIFI_MAX_SSID_LEN);
        memcpy(info->ssid, tmp+1, tmp_len-2);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    else{
        return;
    }
    // rssi
    if(tmp != NULL){
        tmp_len = strlen(tmp);
        memcpy(rssi, tmp, tmp_len);
        info->rssi = atoi(rssi);
        tmp = strtok_r(NULL, ",", &saveptr);
    }
    else{
        return;
    }
    // mac
    if(tmp != NULL){
        tmp_len = strlen(tmp);
        memcpy(mac, tmp+1, 17);
        tmp = strtok_r(NULL, ",", &saveptr);
        mac_str2hex((char *)(info->bssid), mac);
    }
    else{
        return;
    }
    // channel
    if(tmp != NULL){
        tmp_len = strlen(tmp);
        memcpy(channel, tmp, tmp_len);
        info->frequency = ChannelToFrequency(atoi(channel));
    }
    else{
        return;
    }
    info->band = HOTSPOT_BAND_TYPE_2G;
}
void PrintScanInfo(WifiScanInfo *info, int size)
{
    if(info == NULL)
        return;
    char mac[18]={0};
    for(int i=0; i<size; i++){
        mac_hex2str(mac, (char *)(info[i].bssid));
        printf("Hotspot : %s,%s,%d,%d,%d\n", info[i].ssid, mac, info[i].securityType, info[i].rssi, info[i].frequency);
    }
}
// 字符串中有“ "\, ” 需要转义” \" \, \\“ 并且SSID和PASSWD都要被双引号包围
// a"b,c\d ---> "a\"b\,c\\d"
int ESP8266_GenerateSSIDAndPassword(char *dst, char *src)
{
    uint8_t num = 1;
    uint8_t i;

    if (dst == NULL)
        return FAILED;
    // 清空数据
    memset(dst, 0, strlen(dst));
    // 头部增加双引号
    dst[0] = '\"';
    for (i = 0; i < strlen(src); i++)
    {
        // 遇到 \," 进行转义
        if (src[i] == '\\' || src[i] == '\"')
        {
            dst[i + num] = '\\';
            num++;
        }
        dst[i + num] = src[i];
    }
    // 尾部增加双引号
    dst[i + num] = '\"';
    return SUCCESS;
}
void PrintScan()
{
    char buf[256]={0};
    // 遍历队列
    QUEUE_NODE *tmp;
    // 遍历
    LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_scanQueue].head, QUEUE_NODE, s_list)
    {
        memcpy(buf, tmp->user_data, g_queueInfo[g_scanQueue].item_size);
        printf("Hotspot : %s\n", buf);
    }
}
char SendWifiCommand(char *cmd, char *args)
{
    // 清空接收队列，防止和上一条指令的应答混合
    QueueClear(g_uartConfig[AT_USART_PORT-1].recvID);
    int res=WIFI_SUCCESS;
    char *send_buf;
    uint8_t cmd_len=0;
    // 求cmd长度
    cmd_len = strlen(cmd);
    if(!strcmp(cmd, WIFI_RESET) || !strcmp(cmd, WIFI_GET_MODE) || !strcmp(cmd, STA_SCAN_HOTSPOT) || !strcmp(cmd, STA_EXIT_HOTSPOT) \
    || !strcmp(cmd, STA_CURRENT_HOTSPOT) || !strcmp(cmd, STA_GET_IP) || !strcmp(cmd, STA_GET_MAC) || !strcmp(cmd, AP_GET_PARAM) \
    || !strcmp(cmd, AP_LIST_CLIENT) || !strcmp(cmd, STA_DISCONNECT)
    ){
        send_buf = (char *)malloc(cmd_len+2);
        if(send_buf == NULL)
            return ERROR_WIFI_NO_MEMORY;
        memcpy(send_buf, cmd, cmd_len);
    }
    else if(!strcmp(cmd, WIFI_SET_MODE))
    {
        // AT+CWMODE=1
        // 申请内存
        send_buf = (char *)malloc(cmd_len+1+2+1);
        if(send_buf == NULL)
            return ERROR_WIFI_NO_MEMORY;
        // 复制指令
        memcpy(send_buf, cmd, cmd_len);
        // 复制参数
        send_buf[cmd_len] = (*args)+'0';
        cmd_len += 1;
    }
    else if (!strcmp(cmd, STA_JOIN_HOTSPOT))
    {
        // AT+CWJAP="Mate 30 Pro 5G","123321123"
        char *ssid, *passwd;
        int ssid_len = strlen(((WifiDeviceConfig *)args)->ssid);
        // 生成ssid
        ssid = (char *)malloc(ssid_len+1+2);
        if(ssid == NULL){
            return ERROR_WIFI_NO_MEMORY;
        }
        ESP8266_GenerateSSIDAndPassword(ssid, ((WifiDeviceConfig *)args)->ssid);
        int pass_len = strlen(((WifiDeviceConfig *)args)->preSharedKey);
        passwd = (char *)malloc(pass_len+1+2);
        if(passwd == NULL){
            free(ssid);
            return ERROR_WIFI_NO_MEMORY;
        }
        // 生成passwd
        ESP8266_GenerateSSIDAndPassword(passwd, ((WifiDeviceConfig *)args)->preSharedKey);
        send_buf = (char *)malloc(cmd_len+ssid_len+2+1+pass_len+2);
        if(send_buf == NULL){
            free(ssid);
            free(passwd);
            return ERROR_WIFI_NO_MEMORY;
        }
        // 复制cmd
        memcpy(send_buf, cmd, cmd_len);
        // 复制ssid
        memcpy(send_buf+cmd_len, ssid, ssid_len+2);
        cmd_len += ssid_len+2;
        // 增加逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // 复制passwd
        memcpy(send_buf+cmd_len, passwd, pass_len+2);
        cmd_len += pass_len+2;
        // 释放内存
        free(ssid);
        free(passwd);
    }
    else if (!strcmp(cmd, STA_SCAN_HOTSPOT_CUSTOM))
    {
        // AT+CWLAP=<ssid>[,<mac>,<channel>,<scan_type>,<scan_time_min>,<scan_time_max>]
        // AT+CWLAP="gblw","12:34:56:78:90:12"
        WifiScanParams *params = (WifiScanParams *)args;
        char *ssid, *bssid;
        char ssid_len = params->ssidLen;
        switch(params->scanType){
            case WIFI_FREQ_SCAN:
            case WIFI_BAND_SCAN:
            return ERROR_WIFI_NOT_SUPPORTED;
            case WIFI_SSID_SCAN:{
                ssid = (char *)malloc(ssid_len+3);
                ESP8266_GenerateSSIDAndPassword(ssid, params->ssid);
                ssid_len += 2;
                // 申请内存
                send_buf = (char *)malloc(cmd_len+ssid_len+2);
                if(send_buf == NULL)
                    return ERROR_WIFI_NO_MEMORY;
                // 复制指令
                memcpy(send_buf, cmd, cmd_len);
                // 复制参数
                memcpy(send_buf+cmd_len, ssid, ssid_len);
                cmd_len += ssid_len;
                free(ssid);
                break;
            }
            case WIFI_BSSID_SCAN:{
                /*************ssid*************/
                ssid = (char *)malloc(ssid_len+3);
                if(ssid == NULL)
                    return ERROR_WIFI_UNKNOWN;
                memset(ssid, 0 ,ssid_len+3);
                ESP8266_GenerateSSIDAndPassword(ssid, params->ssid);
                ssid_len += 2;
                // 申请内存
                send_buf = (char *)malloc(cmd_len+ssid_len+1+19+2);
                if(send_buf == NULL)
                    return ERROR_WIFI_NO_MEMORY;
                // 复制指令
                memcpy(send_buf, cmd, cmd_len);
                // 复制参数
                memcpy(send_buf+cmd_len, ssid, ssid_len);
                cmd_len += ssid_len;
                /*************bssid*************/
                bssid = (char *)malloc(20);
                if(bssid == NULL)
                    return ERROR_WIFI_UNKNOWN;
                memset(bssid, 0 ,20);
                // 前后加双引号
                bssid[0] = '\"';
                bssid[18] = '\"';
                // 将mac地址转换为字符串
                mac_hex2str(bssid+1, params->bssid);
                // 指令后增加逗号
                send_buf[cmd_len] = ',';
                cmd_len += 1;
                // 指令后增加mac地址
                memcpy(send_buf+cmd_len, bssid, 19);
                free(ssid);
                free(bssid);
                break;
            }
        }

    }
    else if (!strcmp(cmd, STA_SET_MAC))
    {
    }
    else if (!strcmp(cmd, STA_SET_IP))
    {
    }
    else if (!strcmp(cmd, STA_CONNECT))
    {
        // AT+CIPSTART="TCP","192.168.4.2",8888\r\n
        uint8_t tmp[64]={0};
        memcpy(tmp, cmd, cmd_len);
        if(((ServerInfo *)args)->protocol == TCP){
            memcpy(tmp+cmd_len, "\"TCP\",\"", 7);
        }
        else if(((ServerInfo *)args)->protocol == UDP){
            memcpy(tmp+cmd_len, "\"UDP\",\"", 7);
        }
        cmd_len += 7;
        memcpy(cmd+cmd_len, ((ServerInfo *)args)->serverIP, strlen(((ServerInfo *)args)->serverIP));
        cmd_len += strlen(((ServerInfo *)args)->serverIP);
        memcpy(tmp+cmd_len, "\",", 2);
        cmd_len += 2;
        char port[6]={0};
        sprintf(port, "%d", ((ServerInfo *)args)->port);
        memcpy(cmd+cmd_len, port, strlen(port));
        cmd_len += strlen(port);
        send_buf = (char *)malloc(cmd_len + 2);
        if(send_buf == NULL){
            return ERROR_WIFI_NO_MEMORY;
        }
        memcpy(send_buf, tmp, cmd_len);
    }
    else if (!strcmp(cmd, STA_SEND))
    {
        // AT+CIPSEND=6\r\n
        send_buf = (char *)malloc(cmd_len + strlen(args) + 2);
        if(send_buf == NULL)
            return ERROR_WIFI_NO_MEMORY;
        memcpy(send_buf, cmd, cmd_len);
        memcpy(send_buf, args, strlen(args));
        cmd_len += strlen(args);
    }
    else if (!strcmp(cmd, AP_SET_MAC))
    {
    }
    else if (!strcmp(cmd, AP_SET_IP))
    {
    }
    else if (!strcmp(cmd, AP_SET_PARAM))
    {
        // AT+CWSAP_DEF=<ssid>,<pwd>,<chl>,<ecn>[,<max conn>][,<ssid hidden>]
        HotspotConfig *config = (HotspotConfig *)args;
        char ssid[WIFI_MAX_SSID_LEN]={0}, passwd[WIFI_MAX_KEY_LEN]={0};
        // ssid
        // memcpy(ssid, config->ssid, strlen(config->ssid));
        ESP8266_GenerateSSIDAndPassword(ssid, config->ssid);
        uint8_t ssid_len = strlen(ssid);
        // passwd
        // memcpy(passwd, config->preSharedKey, strlen(config->preSharedKey));
        ESP8266_GenerateSSIDAndPassword(passwd, config->preSharedKey);
        uint8_t pass_len = strlen(passwd);
        // channel
        char ch[4] = {0};
        sprintf(ch, "%d", config->channelNum);
        uint8_t ch_len = strlen(ch);
        // ecn
        char ecn='0';
        switch(config->securityType){
            case WIFI_SEC_TYPE_INVALID: return ERROR_WIFI_INVALID_ARGS;
            case WIFI_SEC_TYPE_SAE: return ERROR_WIFI_INVALID_ARGS;
            case WIFI_SEC_TYPE_OPEN: ecn = '0'; break;
            case WIFI_SEC_TYPE_PSK: ecn = '2'; break;
            case WIFI_SEC_TYPE_WEP: ecn = '1'; break; 
        }
        // 申请内存
        send_buf = (char *)malloc(cmd_len + ssid_len + 1 + pass_len + 1 + ch_len + 1 + 1 + 2);
        if(send_buf == NULL){
            return ERROR_WIFI_NO_MEMORY;
        }
        // 复制cmd
        memcpy(send_buf, cmd, cmd_len);
        // 复制ssid
        memcpy(send_buf+cmd_len, ssid, ssid_len);
        cmd_len += ssid_len;
        // 逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // 复制passwd
        memcpy(send_buf+cmd_len, passwd, pass_len);
        cmd_len += pass_len;
        // 逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // ch
        memcpy(send_buf+cmd_len, ch, ch_len);
        cmd_len += ch_len;
        // 逗号
        send_buf[cmd_len] = ',';
        cmd_len += 1;
        // ecn
        send_buf[cmd_len] = ecn;
        cmd_len += 1;
    }
    else if (!strcmp(cmd, AP_SET_DHCP))
    {
    }
    printf("send cmd 2 %d\n", cmd_len);
    // 复制指令的结尾\r\n
    memcpy(&send_buf[cmd_len], "\r\n", 2);
    //send_buf[cmd_len] = '\r';
    //send_buf[cmd_len+1] = '\n';
    cmd_len += 2;
    printf("send cmd 3\n");
    // 发送完整指令
    res = IoTUartWrite(AT_USART_PORT, (unsigned char *)send_buf, cmd_len);
    // 释放内存
    free(send_buf);
    if(res != cmd_len)
        return ERROR_WIFI_UNKNOWN;
    return WIFI_SUCCESS;
}

int8_t WaitWifiResponse(char *cmd, char *result, uint32_t timeout)
{
    printf("wait rsp\n");
    // \r\nOK\r\n    \r\nFAIL\r\n   \r\nERROR\r\n   ready
    uint32_t rsp_len=0, wifi_delay=0, cur_len;
    int8_t res = WIFI_SUCCESS;
    memset(rsp_buf, 0, 1024);
    delay_ms(2000);
    while((strstr(rsp_buf, "\r\nOK\r\n")==NULL) && (strstr(rsp_buf, "\r\nFAIL\r\n")==NULL) && (strstr(rsp_buf, "\r\nERROR\r\n")==NULL) && (strstr(rsp_buf, "ready")==NULL)){
        // 得到当前串口队列的数据长度
        cur_len = g_queueInfo[g_uartConfig[AT_USART_PORT-1].recvID].cur_len;   
        // 读取当前串口所有数据   
        IoTUartRead(AT_USART_PORT, (unsigned char *)(&rsp_buf[rsp_len]), cur_len);
        // 修改总长度
        rsp_len += cur_len;
        // 等待超时
        if(wifi_delay++ > timeout){
            res = ERROR_WIFI_UNKNOWN;
            break;
        }
        delay_ms(1000);
        // printf("rsp:%s\n", rsp_buf);
    }
    // 打开回显功能，每次应答都包含当前cmd
    if (strstr(rsp_buf, cmd) == NULL)
        return ERROR_WIFI_UNKNOWN;
    // 错误的指令
    if (strstr(rsp_buf, "\r\nERROR\r\n") != NULL){
        printf("rsp:%s\n", rsp_buf);
        if(strstr(cmd, STA_CONNECT) == NULL){
            return ERROR_WIFI_INVALID_ARGS;
        }
    }
    // 逐条开始解析每个指令的应答信息
    if(!strcmp(cmd, WIFI_RESET)){
        // 复位
        if(strstr(rsp_buf, "\r\nOK\r\n"))
            res = WIFI_SUCCESS;
        else
            res = ERROR_WIFI_UNKNOWN;
    }
    else if(!strcmp(cmd, WIFI_SET_MODE)){
        // AT+CWMODE=1\r\n\r\nOK\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n")){
            *result = STA;
            return WIFI_SUCCESS;
        }
    }
    else if (!strcmp(cmd, WIFI_GET_MODE))
    {
        // AT+CWMODE?\r\n
        // +CWMODE:3\r\n
        // \r\nOK\r\n
        if(result == NULL)
            res = ERROR_WIFI_INVALID_ARGS;
        char *tmp = strstr(rsp_buf, "+CWMODE:");
        // 回传模式值到第二个参数result
        if(tmp != NULL)
            *result = tmp[8];
    }
    // AT+CWMODE?\r\n
    // +CWMODE:3\r\n
    // \r\nOK\r\n
    else if (!strcmp(cmd, STA_SCAN_HOTSPOT) || !strcmp(cmd, STA_SCAN_HOTSPOT_CUSTOM)){
        // AT+CWLAP\r\n
        // +CWLAP:(4,"Xiaomi_9F9E",-80,"f0:b4:29:e2:9f:9f",1,-7,0)\r\n
        // +CWLAP:(4,"DoMyNet_301",-89,"c8:5b:a0:ca:05:fe",1,-39,0)\r\n
        // \r\nOK\r\n
        if (strstr(rsp_buf, "\r\nOK\r\n")){
            char *tmp, *saveptr;
            char tmp_res[128];
            // 分割字符串
            tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
            while(tmp != NULL){
                // 得到有效数据
                if(strstr(tmp, "+CWLAP:(")){
                    memset(tmp_res, 0, 128);
                    memcpy(tmp_res, tmp+8, strlen(tmp)-9);
                    QueueIn(g_scanQueue, tmp_res);
                }
                tmp = strtok_r(NULL, "\r\n", &saveptr);
            }
        }
        else{
            res = ERROR_WIFI_UNKNOWN;
        }
    }
    else if (!strcmp(cmd, STA_JOIN_HOTSPOT))
    {
        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // WIFI CONNECTED\r\n
        // WIFI GOT IP\r\n
        // \r\nOK\r\n

        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // +CWJAP_DEF:3\r\n  
        // \r\nFAIL\r\n

        // AT+CWJAP_DEF="Mate 30 Pro 5G","123321123"\r\n
        // +CWJAP_DEF:3\r\n
        // \r\nERROR\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n"))
            res = WIFI_SUCCESS;
        else if(strstr(rsp_buf, "\r\nFAIL\r\n")){
            char *tmp = strstr(rsp_buf, "+CWJAP:");
            switch(tmp[11]){
                case '1': res = ERROR_WIFI_BUSY; break;
                case '2': res = ERROR_WIFI_INVALID_PASSWORD; break;
                case '3': res = ERROR_WIFI_NOT_AVAILABLE; break;
                case '4': res = ERROR_WIFI_UNKNOWN; break;
                default: res = ERROR_WIFI_UNKNOWN; break;
            }
        }

    }
    else if (!strcmp(cmd, STA_EXIT_HOTSPOT))
    {
        // AT+CWQAP\r\n
        // \r\nOK\r\n
        // WIFI DISCONNECT\r\n
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_CURRENT_HOTSPOT))
    {
        // AT+CWJAP_CUR?\r\n
        // +CWJAP_CUR:"Mate 30 Pro 5G","1a:56:21:fe:c7:31",1,-63, 0\r\n
        // \r\nOK\r\n

        // AT+CWJAP_CUR?\r\n
        // No AP\r\n
        // \r\nOK\r\n
        char *tmp = strstr(rsp_buf, "+CWJAP_CUR:");
        char *saveptr;
        if(tmp != NULL){
            char *tmp_res;
            char bssid[18]={0}, channel[4]={0}, rssi[5]={0};
            // ssid
            tmp_res = strtok_r(tmp, ",", &saveptr);
            memcpy(((WifiLinkedInfo *)result)->ssid, tmp_res+12, strlen(tmp_res)-12-1);
            // bssid
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(bssid, tmp_res+1, 17);
            mac_str2hex((char *)(((WifiLinkedInfo *)result)->bssid), bssid);
            // channel
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(channel, tmp_res, strlen(tmp_res));
            ((WifiLinkedInfo *)result)->frequency = ChannelToFrequency(atoi(channel));
            // rssi
            tmp_res = strtok_r(NULL, ",", &saveptr);
            memcpy(rssi, tmp_res, strlen(tmp_res));
            ((WifiLinkedInfo *)result)->rssi = atoi(rssi);
            ((WifiLinkedInfo *)result)->connState = WIFI_CONNECTED;
            res = WIFI_SUCCESS;
        }else if(strstr(rsp_buf, "No AP\r\n")){
            ((WifiLinkedInfo *)result)->connState = WIFI_DISCONNECTED;
            res = ERROR_WIFI_NOT_AVAILABLE;
        }

    }
    else if (!strcmp(cmd, STA_GET_IP))
    {
        // AT+CIPSTA?\r\n
        // +CIPSTA:ip:"192.168.43.90"\r\n
        // +CIPSTA:gateway:"192.168.43.1"\r\n
        // +CIPSTA:netmask:"255.255.255.0"\r\n
        // \r\nOK\r\n

        // AT+CIPSTA?\r\n
        // +CIPSTA:ip:"0.0.0.0"\r\n
        // +CIPSTA:gateway:"0.0.0.0"\r\n
        // +CIPSTA:netmask:"0.0.0.0"\r\n
        // \r\nOK\r\n
        char *tmp, *saveptr;
        tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
        // +CIPSTA:ip:"192.168.43.90"
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        char tmp_info[36] = {0};
        memcpy(tmp_info, tmp+12, strlen(tmp)-12-1);
        ((IpInfo *)result)->ipAddress = ip_to_int(tmp_info);
        // +CIPSTA:gateway:"192.168.43.1"
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        memset(tmp_info, 0, 36);
        memcpy(tmp_info, tmp+17, strlen(tmp)-17-1);
        ((IpInfo *)result)->netGate = ip_to_int(tmp_info);
        // +CIPSTA:netmask:"255.255.255.0"
        tmp = strtok_r(NULL, "\r\n", &saveptr);
        memset(tmp_info, 0, 36);
        memcpy(tmp_info, tmp+17, strlen(tmp)-17-1);
        ((IpInfo *)result)->netMask = ip_to_int(tmp_info);
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_GET_MAC))
    {
        // AT+CIPSTAMAC?\r\n
        // +CIPSTAMAC:"5c:cf:7f:14:1b:2b"\r\n
        // \r\nOK\r\n
        char *tmp;
        char tmp_mac[18]={0};
        tmp = strstr(rsp_buf, "+CIPSTAMAC:");
        memcpy(tmp_mac, tmp+12, 17);
        mac_str2hex(result, tmp_mac);
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_CONNECT))
    {
        // AT+CIPSTART="TCP","192.168.43.131",6000\r\n
        // CONNECT\r\n
        // \r\nOK\r\n

        // AT+CIPSTART="TCP","192.168.43.131",6000\r\n
        // ALREADY CONNECTED\r\n
        // \r\nERROR\r\n

        // AT+CIPSTART="TCP","192.168.43.131",6001\r\n
        // \r\nERROR\r\n
        // CLOSED\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n") || strstr(rsp_buf, "ALREADY CONNECTED\r\n"))
            res = WIFI_SUCCESS;
        else
            res = ERROR_WIFI_INVALID_ARGS;
    }
    else if (!strcmp(cmd, STA_DISCONNECT))
    {
        // AT+CIPCLOSE\r\n
        // CLOSED\r\n
        // \r\nOK\r\n
        res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, STA_SEND))
    {
        // AT+CIPSEND=10\r\n
        // \r\nOK\r\n
        // >空格 
        // \r\nRecv 10 bytes\r\n
        // \r\nSEND OK\r\n

        // AT+CIPSEND=6\r\n
        // \r\nOK\r\n
        // > 
        // \r\nRecv 6 bytes
        // \r\nCLOSED
        // \r\nSEND FAIL\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n>") && !strstr(rsp_buf, "\r\nCLOSED"))
            res = WIFI_SUCCESS;
        else
            res = ERROR_WIFI_UNKNOWN;

    }
    else if (!strcmp(cmd, AP_GET_PARAM))
    {
        // AT+CWSAP_CUR?\r\n
        // +CWSAP_CUR:"ESP_141B2B","12345678",1,0,4,0\r\n
        // \r\nOK\r\n

        // AT+CWSAP_CUR?\r\n
        // \r\nERROR\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n")){
            res = WIFI_SUCCESS;
            char *tmp, *saveptr;
            tmp = strtok_r(rsp_buf, "\r\n", &saveptr);
            // +CWSAP_CUR:"ESP_141B2B","12345678",1,0,4,0
            tmp = strtok_r(NULL, "\r\n", &saveptr);
            // +CWSAP_CUR:"ESP_141B2B"
            tmp = strtok_r(NULL, ",", &saveptr);
            memcpy(((HotspotConfig *)result)->ssid, tmp+12, strlen(tmp)-12-1);
            // passwd
            tmp = strtok_r(NULL, ",", &saveptr);
            memcpy(((HotspotConfig *)result)->preSharedKey, tmp+1, strlen(tmp)-2);
            // channel
            tmp = strtok_r(NULL, ",", &saveptr);
            ((HotspotConfig *)result)->channelNum = atoi(tmp);
            // ecn
            tmp = strtok_r(NULL, ",", &saveptr);
            switch(tmp[0]){
                case '0': ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_OPEN; break;
                case '1': ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_WEP; break;
                case '2': 
                case '3': 
                case '4': 
                case '5': ((HotspotConfig *)result)->securityType = WIFI_SEC_TYPE_PSK; break;
            }
            ((HotspotConfig *)result)->band = HOTSPOT_BAND_TYPE_2G;
        }
    }
    else if (!strcmp(cmd, AP_SET_PARAM))
    {
        // AT+CWSAP_CUR="ESP8266","12345678",5,3\r\n
        // \r\nOK\r\n

        // AT+CWSAP_CUR="ESP8266","12345678",5,3\r\n
        // \r\nERROR\r\n
        if(strstr(rsp_buf, "\r\nOK\r\n"))
            res = WIFI_SUCCESS;
    }
    else if (!strcmp(cmd, AP_LIST_CLIENT))
    {
        // AT+CWLIF\r\n
        // 192.168.4.2,02:7d:81:bb:6d:63\r\n
        // 192.168.4.3,98:01:a7:9f:5e:9d\r\n
        // \r\nOK\r\n

        // AT+CWLIF\r\n
        // \r\nOK\r\n

        // AT+CWLIF\r\n
        // \r\nERROR\r\n
        if(strstr(cmd, "\r\nOK\r\n")){
            res = WIFI_SUCCESS;
            char *tmp, *saveptr;
            tmp = strtok_r(rsp_buf, "\r\nOK\r\n", &saveptr);
            tmp = strtok_r(tmp, "\r\n", &saveptr);
            tmp = strtok_r(NULL, "\r\n", &saveptr);
            while(tmp != NULL){
                QueueIn(g_stationQueue, tmp);
                tmp = strtok_r(NULL, "\r\n", &saveptr);
            }
        }

    }
    // WIFI DISCONNECT
    return res;
}

WifiErrorCode ESP8266_ConnectTo(char *ip, uint16_t port, ProtocolType type)
{
    // AT+CIPSTART="TCP","iot.espressif.cn",8000
    WifiErrorCode res;
    ServerInfo info={0};
    memcpy(info.serverIP, ip, strlen(ip));
    info.port = port;
    info.protocol = type;
    res = SendWifiCommand(STA_CONNECT, (char *)(&info));
    if(res == WIFI_SUCCESS){
        res = WaitWifiResponse(STA_CONNECT, NULL, WIFI_TIMEOUT);
        if(res == WIFI_SUCCESS){
            printf("Connect to server %s OK\n", ip);
        }else{
            printf("Connect to server %s Failed\n", ip);
        }
    }
    return res;
}

WifiErrorCode ESP8266_DisConnect()
{
    WifiErrorCode res;
    res = SendWifiCommand(STA_DISCONNECT, NULL);
    if(res == WIFI_SUCCESS){
        res = WaitWifiResponse(STA_DISCONNECT, NULL, WIFI_TIMEOUT);
        if(res == WIFI_SUCCESS){
            printf("DisConnect from server\n");
        }
    }
    return res;
}

int ESP8266_Send(char *msg, int msglen)
{
    WifiErrorCode res;
    uint8_t len[7]={0};
    sprintf((char *)len, "%d", msglen);
    res = SendWifiCommand(STA_SEND, (char *)len);
    if(res == WIFI_SUCCESS){
        res = WaitWifiResponse(STA_SEND, NULL, WIFI_TIMEOUT);
        if(res == WIFI_SUCCESS){
            int cnt;
            cnt = IoTUartWrite(AT_USART_PORT, (unsigned char *)msg, msglen);
            if(cnt == msglen){
                res = WIFI_SUCCESS;
            }
            else{
                res = ERROR_WIFI_UNKNOWN;
            }
        }
    }
    return res;
}

// 由于串口收到的数据是 +IPD,23:123 类型，因此需要将数据解析到另一个队列中
int ESP8266_Recv(char *recvBuf, int recvLen, uint32_t timeout)
{
    // 检测参数
    if(recvBuf == NULL)
        return ERROR_WIFI_NO_MEMORY;
    // 创建队列
    if(g_ESP8266_MsgQueue == 0xff){
        if(QueueCreate(&g_ESP8266_MsgQueue, 1, 4096))
            return ERROR_WIFI_NO_MEMORY;
    }
    uint16_t cur_len;
    uint32_t wifi_delay=0;
    while(1){
        // 串口数据长度
        cur_len = g_queueInfo[g_uartConfig[AT_USART_PORT-1].recvID].cur_len;
        if(cur_len > 0){
            char *tmp_buf = (char *)malloc(cur_len);
            if(tmp_buf == NULL)
                return ERROR_WIFI_NO_MEMORY;
            // 读取串口数据
            memset(tmp_buf, 0, cur_len);
            IoTUartRead(AT_USART_PORT, (unsigned char *)tmp_buf, cur_len);
            // 解析数据
            char *tmp, tmp_len[7] = {0};
            // 照到头部
            tmp = strstr(tmp_buf, "+IPD,");
            while(tmp != NULL){
                // 找长度
                uint16_t pos;
                for(pos=5; ; pos++){
                    if(tmp[pos] == ':')
                        break;
                }
                // 提取长度
                memset(tmp_len, 0, 7);
                memcpy(tmp_len, tmp+5, pos-5);
                // 保存有效数据
                for(uint16_t i=0; i<atoi(tmp_len); i++){
                    QueueIn(g_ESP8266_MsgQueue, &tmp[pos+i+1]);
                }
                // 查找第二条数据
                tmp = strstr(tmp+pos+1+atoi(tmp_len), "+IPD,");
            }
            free(tmp_buf);
        }
        // 8266队列长度大于实际要读取的数据长度，则不需要继续读取串口，可以退出
        if(g_queueInfo[g_ESP8266_MsgQueue].cur_len >= recvLen)
            break;
        if(wifi_delay++ > timeout)
            break;
        delay_ms(1000);
    }
    // 如果8266队列长度cur_len小于需要的长度recvLen，那只能读取cur_len个数据；否则读取recvLen个数据
    uint16_t real_len = g_queueInfo[g_ESP8266_MsgQueue].cur_len<recvLen?g_queueInfo[g_ESP8266_MsgQueue].cur_len:recvLen;
    // 把8266队列中的数据复制到recvbuf
    for(uint16_t i=0; i<real_len; i++){
        QueueOut(g_ESP8266_MsgQueue, &recvBuf[i]);
    }
    return real_len;
}